package namespace

import (
	"fmt"
	"strings"
	"time"

	"gddgame.cc/galaxy/binocle"
	. "gddgame.cc/galaxy/common/dsl/game"
	"gddgame.cc/galaxy/common/dsl/game/attr"
	"gddgame.cc/galaxy/common/namespaces"
	"gddgame.cc/galaxy/common/namespaces/cooperate"
	"gddgame.cc/galaxy/common/service/generate_name"
	"gddgame.cc/galaxy/common/service/lobby"
	"gddgame.cc/galaxy/common/service/lobby/one"
	"gddgame.cc/galaxy/common/service/pathfinding"
	"gddgame.cc/galaxy/core/models"
	"gddgame.cc/galaxy/core/sdk"
	"gddgame.cc/galaxy/project/breeder/breeder/controller"
	"gddgame.cc/galaxy/project/breeder/breeder/cooperated"
	"gddgame.cc/galaxy/project/breeder/breeder/model"
	"gddgame.cc/galaxy/satellite/formula/nebula"
	"gddgame.cc/galaxy/server/composer"
	"gddgame.cc/galaxy/utils"
	"gddgame.cc/galaxy/utils/def"
)

const (
	Map     nebula.NS = 100
	Manager nebula.NS = 101
)

type Delegate struct {
	*sdk.AppClient
	binocle.App
	*Environment

	mapStore map[string]*cooperated.TypeMap
}

func (d *Delegate) Version() string {
	return d.App.Version()
}

func (d *Delegate) GetUserId(userOpen *models.UserOpen) (int, error) {
	var user model.User
	create, err := controller.Center.FindOrCreateUser(userOpen.Id, &user, func() {
		user.OpenId = userOpen.Id
	})
	if err != nil {
		return 0, err
	}
	if create {
		//updateData := map[string]interface{}{}
	}
	return user.Id, nil
}
func (d *Delegate) Connect(context def.Context, userOpen *models.UserOpen, userId int) {
	_ = controller.Env.RefreshUserStatus(userOpen.Id, false)

	// 登录清空缓存
	_ = controller.Center.CleanUser(userId)
	var user model.User
	if err := controller.Center.GetUser(userId, &user); err != nil {
		return
	}
	if userOpen.LastTime == nil {
		// 第一次登录
		_ = controller.Center.UpdateStatSingle(context, &user, controller.Center.StatData, model.CurrentLogin, 1, false)
		_ = controller.Center.UpdateStatSingle(context, &user, controller.Center.StatData, model.MaxLogin, 1, false)
		return
	}
	// 更新用户语言设置
	language := GetLanguage(context)
	_ = controller.Env.UpdateUserStatus(userOpen.Id, LanguageKey, language)

	location := GetZone(context)
	local := userOpen.LastTime.In(location)
	now := time.Now()
	if local.YearDay() == now.YearDay() {
		// 如果最后一次登录在今天，不统计
		return
	}
	next := local.AddDate(0, 0, 1)
	if next.Day() == now.Day() {
		// 最后一次登录是昨天，连续登录天数+1
		_ = controller.Center.UpdateStatSingle(context, &user, controller.Center.StatData, model.CurrentLogin, 1, false)
		// 更新最大连续登录天数
		_ = controller.Center.UpdateStatSingle(context, &user, controller.Center.StatData, model.MaxLogin, 1, false)
		// 更新登录徽章
		//_ = controller.UpdateBadgeSingle(context, user, model.LoginBadge)
	} else {
		// 最后一次登录大于1天，清空连续登录天数
		_ = controller.Center.UpdateStatSingle(context, &user, controller.Center.StatData, model.CurrentLogin, 1, true)
	}
}
func (d *Delegate) Disconnect(context def.Context, openId string, userId int) {
	_ = controller.Env.RefreshUserStatus(openId, false)
}

func (d *Delegate) SendSharedMessage(userOpen *models.UserOpen, userId int, targetId string) error {
	var user model.User
	if err := controller.Center.FindUser(targetId, &user); err != nil {
		return err
	}
	// 添加分享奖励
	// 给发送分享的人发送
	if _, err := controller.SendShareMessage(d.Environment.Context(), user.Id, userOpen.Id, userOpen.NickName); err != nil {
		return err
	}
	// 给加入人发送
	return nil
}

func (d *Delegate) StartPlay(instance *namespaces.RoomInstance) error {
	return nil
}

func (d *Delegate) GetMapBlock() (byte, byte) {
	return 18, 10
}

func (d *Delegate) GetAccessTokenPolicy(namespace string, token string) map[string]interface{} {
	if namespace == "cooperate" {
		return map[string]interface{}{
			"orbit.chess:rate": 50, // 服务器加快下发速度
		}
	}
	return map[string]interface{}{}
}

func (d *Delegate) GetUserManager() namespaces.UserManager {
	return d
}

func (d *Delegate) GetAiManager() namespaces.AiManager {
	return d
}

func (d *Delegate) GetTypeDefinedManager() cooperate.TypeDefinedManager {
	controller.TM.BindData(d)
	return controller.TM
}

func (d *Delegate) GetMapContent(mapNoId string, content string) cooperate.MapContent {
	//switch content {
	//case "auto":
	//	return &content2.AutoContent{
	//		TypeMap: d.mapStore[mapNoId],
	//	}
	//case "auto_put":
	//	return &content2.AutoPutContent{
	//		TypeMap: d.mapStore[mapNoId],
	//	}
	//}
	return nil
}
func (d *Delegate) GetTypeDefined(mapNoId string) (cooperate.TypeDefined, *cooperate.MapInfo, int) {
	mapItem, mapNo, err := controller.GetMapNo(d.Environment.Context(), mapNoId)
	mapInfo := &cooperate.MapInfo{}
	if err != nil {
		fmt.Println(err)
		return nil, nil, 0
	}
	mapInfo.Content = mapNo.Content
	mapInfo.Data = mapItem.Data
	if mapItem.CostList != nil {
		mapInfo.NodeCostList = make([]pathfinding.NodeCost, len(mapItem.CostList))
		for index, data := range mapItem.CostList {
			mapInfo.NodeCostList[index] = pathfinding.NodeCost{
				Type: utils.ToByte(data.Key),
				Cost: utils.ToInt(data.Value),
			}
		}
	}
	if mapItem.MessageList != nil {
		mapInfo.MessageRangeList = make([]uint16, 255)
		for _, data := range mapItem.MessageList {
			mapInfo.MessageRangeList[utils.ToByte(data.Key)] = utils.ToUint16(utils.ConcatInt(controller.Center.SyncData.MappingLevel(data.Value)))
		}
	}
	list, err := controller.GetNodes(d.Environment.Context(), mapItem.Id)
	if err != nil {
		return nil, mapInfo, mapItem.Version
	}
	s := make(map[string]attr.AttrEffectSlice, len(list))
	for _, o := range list {
		p := (&pathfinding.Vector2{
			X: int16(o.X),
			Y: int16(o.Y),
		}).Encode()
		t := make(attr.AttrEffectSlice, len(o.AttrEffect))
		for i, a := range o.AttrEffect {
			t[i] = attr.AttrEffect{Index: a.Index, Value: a.Value}
		}
		s[utils.ToString(p)] = t
	}
	var td cooperate.TypeDefined
	switch mapItem.Content {
	case "strategy":
		strategyTD := cooperated.NewStrategyMap(controller.TM)
		d.mapStore[mapNoId] = strategyTD
		td = strategyTD
	}
	return td, mapInfo, mapItem.Version
}

func (d *Delegate) StartSuccess(mapNoId string) {
	_, _ = controller.StartMap(d.Environment.Context(), d.Namespace(), mapNoId)
}

func (d *Delegate) StopSuccess(mapNoId string) {
	// 通知释放
}

func (d *Delegate) PreLoadMap(node string) {
	controller.PreLoadMap(node)
}

func (d *Delegate) GetAccountId(userId int) (int, int) {
	var user model.User
	if err := controller.Center.GetUser(userId, &user); err != nil {
		return 0, 0
	}
	return user.AccountId, user.Identity
}
func (d *Delegate) SaveAccount(userId int, id int, identity int) error {
	var user model.User
	if err := controller.Center.GetUser(userId, &user); err != nil {
		return err
	}
	err := controller.Center.UpdateUser(&user, map[string]interface{}{
		"account_id": id,
		"identity":   identity,
	})
	return err
}

func (d *Delegate) ApplyAi() (string, int, int) {
	user, err := controller.FindFreeAi(d.Environment.Context())
	if err != nil {
		// 申请新的账号
		userOpen, err := d.RegisterGuest()
		if err != nil {
			fmt.Println("apply", err)
			return "", 0, 0
		}
		nickName := generate_name.Random()
		if err := d.ChangeOpen(userOpen.Id, nickName, ""); err != nil {
			return "", 0, 0
		}
		user = &model.User{
			OpenId:   userOpen.Id,
			IsSystem: true,
			Status:   true,
		}
		if err := controller.Center.CreateUser(userOpen.Id, user); err != nil {
			return "", 0, 0
		}
		return user.OpenId, user.Id, user.AccountId
	}
	if user != nil {
		if err := controller.Center.UpdateUser(user, map[string]interface{}{
			"status": true,
		}); err != nil {
			return "", 0, 0
		}
		return user.OpenId, user.Id, user.AccountId
	}
	return "", 0, 0
}
func (d *Delegate) GenerateAi(openId string, accountId int, identity int) (int, error) {
	var user model.User
	if create, err := controller.Center.FindOrCreateUser(openId, &user, func() {
		user.OpenId = openId
		user.AccountId = accountId
		user.Identity = identity
		user.IsSystem = true
		user.Status = true
	}); err != nil {
		return 0, err
	} else if !create {
		if err := controller.Center.UpdateUser(&user, map[string]interface{}{
			"account_id": accountId,
			"identity":   identity,
			"status":     true,
			"is_system":  true,
		}); err != nil {
			return 0, err
		}
	}
	return user.Id, nil
}
func (d *Delegate) ReleaseAi(userId int) {
	_ = controller.ReleaseAi(d.Environment.Context(), userId)
}
func (d *Delegate) ApplyManager(id string, node string, number int) []string {
	// 一次申请一张地图
	// 如果申请有返回，秒级别继续申请
	// 如果申请没有返回，分钟级别申请
	mapNo, err := controller.FindFreeMap(d.Environment.Context(), d.Namespace(), id, node)
	if err != nil {
		return []string{}
	}
	if mapNo != nil {
		return []string{mapNo.Id}
	}
	// 判断数量，释放一个地图
	item, err := controller.TransferMap(d.Environment.Context(), d.Namespace(), id, node, number)
	if err != nil {
		return []string{}
	}

	if item != nil {
		info := strings.Split(item.AiNode, "/")
		if len(info) == 2 {
			controller.Env.ReleaseManager(info[0], info[1], item.Id)
		}
	}
	return []string{}
}
func (d *Delegate) OnReleaseManager(id string, node string, mapNoIds []string) {
	for _, m := range mapNoIds {
		_ = controller.ReleaseMap(d.Environment.Context(), d.Namespace(), m, id, node)
	}
}
func (d *Delegate) JoinMap(userId int, mapNoId string, ai bool) (need bool, have bool) {
	_, b, err := controller.JoinNo(d.Environment.Context(), mapNoId, userId, ai)
	if err != nil {
		return true, !b
	}
	return false, false
}

func (d *Delegate) GetAccount(accountId int) *model.User {
	user, _ := controller.GetUserByAccount(d.Environment.Context(), accountId)
	return user
}
func (d *Delegate) GetUnit(userUnitId string) *model.UserUnit {
	userUnit, _ := controller.GetUnit(d.Environment.Context(), userUnitId)
	return userUnit
}
func (d *Delegate) DefaultMap() string {
	mapItem, err := controller.GetMap(controller.Env.Context(), 0)
	if err != nil {
		return ""
	}
	var mapNoId string
	if d.App.Namespace() == "local" {
		mapNoId = mapItem.EncodeNo(0)
	} else {
		mapNoId = mapItem.EncodeNo(mapItem.No)
	}
	return mapNoId
}

func (d *Delegate) GetMapNodes(mapNoId string) []string {
	if v, ok := controller.Center.MapNodes[mapNoId]; ok {
		return v
	}
	return []string{}
}
func (d *Delegate) GetNodeMaps(node string) []string {
	if v, ok := controller.Center.NodeMaps[node]; ok {
		return v
	}
	return []string{}
}
func InitHandler(builder composer.Builder, client *sdk.AppClient, handler nebula.NamespaceHandler) error {
	var agent binocle.App
	builder.Factory("agent", &agent)
	delegate := &Delegate{AppClient: client, App: agent, Environment: controller.Env}

	delegate.mapStore = map[string]*cooperated.TypeMap{}

	controller.Agent = agent

	// 匹配服务
	lobbyServer := lobby.Default()
	lobbyServer.RegisterMatch(one.Default)

	controller.Env.AuthManager = namespaces.AuthHandler(builder, handler(AUTH), client, delegate)
	controller.Env.SceneManager = namespaces.SceneHandler(builder, handler(SCENE), client, delegate)
	controller.Env.RoomManager = namespaces.RoomHandler(builder, handler(ROOM), client, delegate)
	controller.Env.TeamManager = namespaces.TeamHandler(builder, handler(TEAM), client, delegate)
	controller.Env.CooperateManager = namespaces.CooperateHandler(builder, handler(COOPERATE), client, delegate)
	if err := controller.Env.SetNamespace(); err != nil {
		return err
	}

	MapHandler(builder, client, handler(Map))

	InfoHandler(builder, client, handler(INFO), delegate)
	ManageHandler(builder, client, handler(Manager))

	if err := delegate.AuthManager.Depends(); err != nil {
		return err
	}
	if err := delegate.SceneManager.Depends(); err != nil {
		return err
	}
	if err := delegate.RoomManager.Depends(); err != nil {
		return err
	}
	if err := delegate.TeamManager.Depends(); err != nil {
		return err
	}
	if err := delegate.CooperateManager.Depends(); err != nil {
		return err
	}

	return nil
}
